import { Controller, Get, Inject, Query, Response } from '@nestjs/common';
import { ChildProcessService } from './child-process.service';
import { execFile, execSync, spawn } from 'node:child_process';
import path, { join } from 'node:path';
import { readFileSync } from 'node:fs';
import { ClientProxy } from '@nestjs/microservices';
import { Observable } from 'rxjs';
const JSZip = require('jszip');

@Controller('child-process')
export class ChildProcessController {
  @Inject('SUM_SERVICE')
  private readonly sumService: ClientProxy;

  constructor(private readonly childProcessService: ChildProcessService) {}

  // 通过fork 启动子进程, 在子进程中执行 child.js 文件，处理耗时任务。
  @Get('start')
  async start_child_process(@Query() query: any) {
    try {
      // 准备要处理的数据 - 使用查询参数或默认数组
      const data = this.prepareData(query);

      // 使用服务层创建并执行子进程任务
      const result =
        await this.childProcessService.createChildProcessTask(data);

      // 获取当前活跃子进程数量
      const activeProcesses = this.childProcessService.getActiveProcessCount();

      // 返回处理结果和系统信息
      return {
        message: '子进程任务执行成功',
        result,
        systemInfo: {
          activeProcesses,
          timestamp: new Date().toISOString(),
        },
      };
    } catch (error) {
      // 错误处理
      return {
        success: false,
        message: '子进程任务执行失败',
        error: error.message || '未知错误',
      };
    }
  }

  // 通过exec 执行 命令，通过 execFile 执行 .cmd 文件
  @Get('exec')
  async operator_exec() {
    const nodeV = execSync('node -v').toString();
    const npmV = execSync('npm -v').toString();
    // execSync('start chrome http://www.baidu.com --incognito');
    const systemInfo = {
      nodeV,
      npmV,
      timestamp: new Date().toISOString(),
    };
    const cmd_path = path.join(__dirname, '../../child-process/files/bat.cmd');
    console.log(cmd_path);
    // 在 Windows 环境中，.cmd 文件需要通过 cmd.exe 来执行
    execFile('cmd.exe', ['/c', cmd_path], (error, stdout, stderr) => {
      if (error) {
        console.error('执行错误:', error);
        return;
      }
      console.log('标准输出:', stdout.toString());
    });

    return systemInfo;
  }

  // 通过spawn 拉起 image-tiny.exe
  @Get('spawn')
  async operator_spawn() {
    const cmd_path = path.join(
      __dirname,
      '../../child-process/files/image-tiny.exe',
    );
    const spawn_handle = spawn('cmd.exe', ['/c', cmd_path]);
    spawn_handle.stdout.on('data', (data) => {
      console.log(`stdout: ${data}`);
    });
    spawn_handle.stderr.on('data', (data) => {
      console.error(`stderr: ${data}`);
    });
    spawn_handle.on('close', (code) => {
      console.log(`子进程退出: ${cmd_path}，退出码 ${code}`);
    });
    return 'ok';
  }

  // 通过jszip 生成压缩文件，前端浏览器访问该接口直接下载
  @Get('jszip')
  async operator_jszip(@Response() res: import('express').Response) {
    const zip = new JSZip();

    try {
      const pathPackage = join(__dirname, '../../package.json');
      const packageJSON = readFileSync(pathPackage, 'utf8');
      zip.file('package.json', packageJSON);
    } catch (error) {
      console.error('生成压缩文件package.json失败:', error);
    }

    zip.file('image.jpg', Buffer.from('image data'));
    zip.file('hello.txt', 'Hello, World!');
    const content = await zip.generateAsync({ type: 'nodebuffer' });

    // 设置响应头，使浏览器直接下载文件
    res.setHeader('Content-Type', 'application/zip');
    res.setHeader('Content-Disposition', 'attachment; filename=compressed.zip');
    res.setHeader('Content-Length', content.length);

    // 发送压缩文件内容
    res.send(content);
  }
  // sum_microservice 调用微服务 sum 计算数组元素和
  @Get('microservice_sum')
  async sum_microservice(@Query() query: any): Promise<Observable<number>> {
    const arr = (query.arr || '1,2,3,4,5,6,7,8,9,10').split(',').map(Number);
    //如果那边是 @MessagePattern 声明的方法，这边要用 send 方法调用。
    //如果并不需要返回消息的话，可以用 @EventPattern 声明。用 emit 方法调用。
    const total = await this.sumService.send<number>(
      {
        cmd: 'sum',
      },
      arr,
    );
    this.sumService.emit('log', `数组 ${arr} 的元素和为 55`);
    return total;
  }

  /**
   * 准备要发送给子进程的数据
   * @param query 查询参数
   * @returns 处理后的数据
   */
  private prepareData(query: any): any {
    // 如果查询参数中包含数据，使用它
    if (query.data) {
      try {
        return JSON.parse(query.data);
      } catch (e) {
        // 如果解析失败，返回默认数据
        console.warn('解析查询参数数据失败，使用默认数据');
      }
    }

    // 返回默认的大数据数组（模拟耗时计算）
    // 生成一个包含1到1000的数组
    return Array.from({ length: 1000 }, (_, i) => i + 1);
  }
}
